package milkyway.hightech.customergui;

import milkyway.hightech.comparators.SortOrder;
import milkyway.hightech.conditions.GiroCondTypes;
import milkyway.hightech.conditions.InvCondTypes;
import milkyway.hightech.customer.BankCustomerView;
import milkyway.hightech.exceptions.EmptyInputException;
import milkyway.hightech.formatter.FormatterTypes;
import milkyway.hightech.money.Currency;

import java.awt.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import java.math.BigInteger;

import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;

import javax.swing.JComboBox;
import javax.swing.JTextField;

/**
 *
 * @author michael
 */
public class CustomerGUIController
{
    private Map<String, Method> methods = new HashMap<String, Method>();
    private Map<String, Class<?>[]> params = new HashMap<String, Class<?>[]>();
    BankCustomerView customer;
    ResourceBundle rb;

    /**
     *
     * @param bank
     */
    public CustomerGUIController(BankCustomerView bank, ResourceBundle rb)
    {
        this.customer = bank;
        this.rb = rb;
        this.getMethods();
        this.getParamTypes();
    }

    /**
     * Stores Methods by name in a map
     */
    private void getMethods()
    {
        Method[] m = BankCustomerView.class.getMethods();

        for (int i = 0; i < m.length; i++)
        {
            methods.put(m[i].getName(), m[i]);
        }
    }

    /**
     * stores method params by methodname in a map
     */
    private void getParamTypes()
    {
        Method[] m = BankCustomerView.class.getMethods();

        for (int i = 0; i < m.length; i++)
        {
            params.put(m[i].getName(), m[i].getParameterTypes());
        }
    }

    /**
     *
     * @param methodName
     * @return
     */
    public Method getMethod(String methodName)
    {
        return methods.get(methodName);
    }

    /**
     *
     * @param methodName
     * @return
     */
    public Class<?>[] getParams(String methodName)
    {
        return params.get(methodName);
    }

    /**
     * invokes the method.
     * @param methodName
     * @param components
     * @return the result of the invoked method.
     * @throws IllegalAccessException
     * @throws IllegalArgumentException
     * @throws InvocationTargetException
     * @throws ClassNotFoundException
     * @throws EmptyInputException
     */
    public Object execute(String methodName, Component[] components)
        throws IllegalAccessException, IllegalArgumentException,
            InvocationTargetException, ClassNotFoundException,
            EmptyInputException
    {
        Method m = methods.get(methodName);
        Object[] param = new Object[params.get(methodName).length];
        int count = 0;

        for (int i = 0; i < components.length; i++)
        {
            if (components[i] instanceof JTextField)
            {
                Component comp = components[i];
                String strPar = ((JTextField)comp).getText();
                Class clazz = params.get(methodName)[count];
                param[count] = getParam(clazz, strPar, methodName, count);
                
                count++;
            }
            
            else if (components[i] instanceof JComboBox)
            {
                Component comp = components[i];
                String strPar = ((JComboBox)comp).getSelectedItem().toString();
                Class clazz = params.get(methodName)[count];
                param[count] = getParam(clazz, strPar, methodName, count);
                
                count++;
            }
        }

        return m.invoke(customer, param);
    }

    /**
     * parses the values from the gui to the right Type
     * @param clazz in which the parameter should be parsed
     * @param param to parse
     * @return the parsed parameter
     * @throws ClassNotFoundException
     */
    private Object getParam(Class clazz, Object param, String methodName,
        int paramCount) throws ClassNotFoundException, EmptyInputException
    {
        String classString = "java.lang.String";
        String classInteger = "java.lang.Integer";
        String classBigInt = "java.math.BigInteger";
        String classGiroCond = "milkyway.hightech.conditions.GiroCondTypes";
        String classInvCond = "milkyway.hightech.conditions.InvCondTypes";
        String classCurrency = "milkyway.hightech.money.Currency";
        String classSortOrder = "milkyway.hightech.comparators.SortOrder";
        String classFormTypes = "milkyway.hightech.formatter.FormatterTypes";
        
        Object newParam = null;
        
        if (param.toString().equals(""))
        {
            String message = rb.getObject("emptyInput").toString();
            Object obj = rb.getObject("formElementValues");
            Map<String, String[]> map = (Map<String, String[]>)obj;
            String inputField = map.get(methodName)[paramCount + 1];
            
            throw new EmptyInputException(message + " " + inputField);
        }
        
        else if (clazz.equals(Class.forName(classString)))
        {
            newParam = param.toString();
        }
        
        else if (clazz.equals(Class.forName(classInteger)))
        {
            newParam = Integer.parseInt(param.toString());
        }
        
        else if (clazz.equals(Class.forName(classBigInt)))
        {
            newParam = new BigInteger(param.toString());
        }
        
        else if (clazz.equals(Class.forName(classGiroCond)))
        {
            newParam = GiroCondTypes.valueOf(param.toString());
        }
        
        else if (clazz.equals(Class.forName(classInvCond)))
        {
            newParam = InvCondTypes.valueOf(param.toString());
        }
        
        else if (clazz.equals(Class.forName(classCurrency)))
        {
            newParam = Currency.valueOf(param.toString());
        }
        
        else if (clazz.equals(Class.forName(classSortOrder)))
        {
            newParam = SortOrder.valueOf(param.toString());
        }
        
        else if (clazz.equals(Class.forName(classFormTypes)))
        {
            newParam = FormatterTypes.valueOf(param.toString());
        }

        return newParam;
    }
}
